﻿using System;
using System.Collections.Generic;
using System.Text;
using SharpPcap;
using PacketDotNet;

namespace Bouyei.NetworkSniffer
{
    public class NetworkCapture
    {
        ICaptureDevice device;

        sealed class Instance
        {
            static Instance()
            { }
            internal static NetworkCapture networkSniffer = new NetworkCapture();
        }

        public static NetworkCapture Singleton
        {
            get {return Instance.networkSniffer; }
        }

        /// <summary>
        /// 捕获数据事件
        /// </summary>
        public CaptureDataEventArgs CaptureDataEventHandler { get; set; }

        //构造
        public NetworkCapture()
        { }

        ~NetworkCapture()
        {
           if(this.device!=null)
           {
               this.device.Close();
           }
        }

        public List<CaptureInfo> GetCaptureDevices()
        {
            CaptureDeviceList cap = CaptureDeviceList.New();
            IEnumerator<ICaptureDevice> items = cap.GetEnumerator();
            List<CaptureInfo> devices = new List<CaptureInfo>(cap.Count);
            int id = 0;
            while (items.MoveNext())
            {
                devices.Add(new CaptureInfo()
                {
                    CaptureDevice = items.Current,
                    CaptureDisplayName = GetCaptureDisplayName(items.Current),
                    CaptureId = id++
                });
            }
            return devices;
        }

        /// <summary>
        /// 开始捕获
        /// </summary>
        /// <param name="device"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public bool StartCapture(ICaptureDevice device, string filter)
        {
            try
            {
                if (this.device != null)
                {
                    this.device.OnPacketArrival -= device_OnPacketArrival;
                    this.device.StopCapture();
                    this.device.Close();
                }
                this.device = device;
                this.device.OnPacketArrival += device_OnPacketArrival;

                int readTimeoutMilliseconds = 1000;
                this.device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
                if (!string.IsNullOrEmpty(filter))
                    this.device.Filter = filter;

                this.device.StartCapture();

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 停止捕获
        /// </summary>
        public void StopCaptrue()
        {
            if(this.device!=null)
            {
                this.device.Close();
            }
        }

        /// <summary>
        /// 设置过滤数据包表达式
        /// </summary>
        /// <param name="filter"></param>
        public void SetCaptureFilter(string filter)
        {
            if(this.device!=null && this.device.Started)
            {
                this.device.Filter = filter;
            }
        }

        void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
           if(CaptureDataEventHandler!=null)
           {
               CaptureDataEventHandler(e.Packet);
           }
        }

        private string GetCaptureDisplayName(ICaptureDevice captureDevice)
        {
            string[] arr = captureDevice.ToString().Split('\n');
            if (arr.Length >= 2)
            {
                return arr[1].Split(':')[1].Trim();
            }
            return string.Empty;
        }
    }
}
